#include "Universal.h"
#include <conio.h>
#include <iostream>
#include <windows.h>

int Universal::EzGetch()
{
#ifdef _MSC_VER
    return _getch();
#else
    return  getch();
#endif
}

int Universal::EzKbhit()
{
#ifdef _MSC_VER
    return _kbhit();
#else
    return  kbhit();
#endif
}

void Universal::EzPutch(int ch)
{
#ifdef _MSC_VER
    _putch(ch);;
#else
    putch(ch);
#endif
}

void Universal::OutputTxt(const char *text, const bool line)
{
    if (text && *text)
    {
        printf("%s%s", text, line ? "\n" : "");
    }
    else
    {
        printf(line ? "\n" : "");
    }
}

void Universal::OutputBool(const int value, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%s%s%s", pre_txt ? pre_txt : "", value ? "true" : "false", post_txt ? post_txt : "", line ? "\n" : "");
}

void Universal::OutputDec(const int64 value, const char *pre_text, const char *post_text, const bool line)
{
    printf("%s%I64d%s%s", pre_text ? pre_text : "", value, post_text ? post_text : "", line ? "\n" : "");
}

void Universal::OutputFloat(const double value, const char *pre_text, const char *post_text, const bool line)
{
    printf("%s%5.2lf%s%s", pre_text ? pre_text : "", value, post_text ? post_text : "", line ? "\n" : "");
}

void Universal::OutputHex02(const byte value, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%02X%s%s", pre_txt ? pre_txt : "", value, post_txt ? post_txt : "", line ? "\n" : "");
}

void Universal::OutputHex04(const ushort value, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%04X%s%s", pre_txt ? pre_txt : "", value, post_txt ? post_txt : "", line ? "\n" : "");
}

void Universal::OutputHex08(const uint value, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%08X%s%s", pre_txt ? pre_txt : "", value, post_txt ? post_txt : "", line ? "\n" : "");
}

void Universal::OutputHex16(const uint64 value, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%016I64X%s%s", pre_txt ? pre_txt : "", value, post_txt ? post_txt : "", line ? "\n" : "");
}

void Universal::OutputIpv4(const uint ip, const char *pre_txt, const char *post_txt, const bool line)
{
    printf("%s%d.%d.%d.%d%s%s", pre_txt ? pre_txt : "", ip >> 24 & 0xFF, ip >> 16 & 0xFF, ip >> 8 & 0xFF, ip >> 0 & 0xFF, post_txt ? post_txt : "",
        line ? "\n" : "");
}

void Universal::OutputErr(const KSError error, const char *func_name, const char *comment)
{
    if (error == KS_OK) {return;}

    HANDLE console_output = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO buffer_info;
    GetConsoleScreenBufferInfo(console_output, &buffer_info);

    SetConsoleTextAttribute(console_output, FOREGROUND_RED | FOREGROUND_INTENSITY);
    const char *chr_error;
    KS_getErrorString(error, &chr_error, KSLNG_DEFAULT);
    printf("ERROR (0x%08X = \'%s\') -\n  %s: %s\n", error, chr_error, func_name, comment);

    SetConsoleTextAttribute(console_output, buffer_info.wAttributes);
    if (KS_getErrorDescription(error, func_name, &chr_error, KSLNG_DEFAULT) == KS_OK)
    {
        OutputTxt(chr_error);
    }
}

#define KSMP_INPUTBUFFERSIZE 256

char *Universal::InputTxt(const char *pre_text, const char *default_val)
{
    printf("%s", pre_text);
    if (default_val && *default_val)
    {
        printf("[%s] ", default_val);
    }

    static char buffer[KSMP_INPUTBUFFERSIZE];
    for (int i = 0;;)
    {
        const int ch = EzGetch();
        if (isprint(ch))
        {
            // 输出输入值
             EzPutch(ch);
        }
        if (ch == '\b')
        {
            if (i > 0)
            {
                --i;
                printf("\b \b");
            }
            continue;
        }
        if (ch == '\r' || i == KSMP_INPUTBUFFERSIZE - 1)
        {
            printf("\n");
            if (i == 0)
                strcpy(buffer, default_val);
            else
                buffer[i] = '\0';
            break;
        }
        if (isprint(ch))
            buffer[i++] = ch;
    }
    return buffer;
}

#undef KSMP_INPUTBUFFERSIZE

int Universal::InputDec(const char *pre_text, const char *default_val)
{
    int dec = 0;
    sscanf(InputTxt(pre_text, default_val), "%d", &dec);
    return dec;
}

int Universal::InputDec(const char *pre_text, int default_val)
{
    char p_buf[32];
    sprintf(p_buf, "%d", default_val);
    return InputDec(pre_text, p_buf);
}

void Universal::WaitTime(const uint time)
{
    const uint delay = time / 10000;
    Sleep(delay);
}

